import * as React from "react";
import type { Key, MapTreeDataResult, TreeItem } from "./interface";
import styles from "./index.less";

/**
 * @file 简单虚拟滚动
 * react-virtualized 不支持React18
 */

interface ItemPosition<T extends Key> {
  index: number;
  top: number;
  height: number;
  item: TreeItem<T>;
}

interface VirtualScrollProps<T extends Key, O = {}> {
  bufferLine?: number;
  treeData: MapTreeDataResult<T, O>;
  expendKeys?: Set<T>;
  children: {
    (item: TreeItem<T> & O, index: number, deepth: number): React.ReactNode;
  };
  refContainer?: React.LegacyRef<HTMLDivElement>;
  style?: React.CSSProperties;
  itemHeight?: (item: TreeItem<T> & O, index: number, deepth: number) => number;
}

const VirtualScroll = function <T extends Key>(props: VirtualScrollProps<T>) {
  const {
    itemHeight = () => 50,
    bufferLine = Math.ceil(document.documentElement.clientHeight / 25),
    treeData: [data_tree, data_map],
    refContainer,
    children: renderItem,
  } = props;
  const [scrollTop, setScrollTop] = React.useState(0);
  const expendKeys = new Set(props.expendKeys || data_map.keys());
  const visibleKeys = new Set<T>();
  const positions: ItemPosition<T>[] = []
  let top = 0;
  function loop(data_tree: TreeItem<T>[]) {
    for (let i = 0; i < data_tree.length; i++) {
      const item = data_tree[i];
      const index = positions.length
      const parent = data_map.get(item.parent_key);
      const height = itemHeight(item, index, item.parent_keys?.length || 0);
      /** 顶级元素不可隐藏 */
      if (!parent) {
        visibleKeys.add(item.key);
        positions.push({
          index, height, top, item
        })
        top += height
      } else if (!item.parent_keys.find((k) => !expendKeys.has(k))) {
        positions.push({
          index, height, top, item
        })
        top += height
      }
      if (item.children) {
        loop(item.children)
      }
    }
  }
  loop(data_tree)
  const beginPosition = positions.find(p => p.top >= scrollTop) || positions[0]
  const beginIndex = Math.max(beginPosition?.index - 5, 0);

  return (
    <div
      ref={refContainer}
      className={styles.virtual_scroll}
      onScroll={function (e: React.UIEvent<HTMLDivElement, UIEvent>) {
        e.persist();
        setScrollTop(e.currentTarget.scrollTop);
      }}
      style={props.style}
    >
      <div className={styles.inner} style={{ height: top }}>
        {positions.slice(beginIndex, beginIndex + bufferLine).map(
          ({ item, index, top, height }) => {
            return <div key={item.key} className={styles.item} style={{ top, height }}>
              {renderItem(item, index, item.parent_keys?.length || 0)}
            </div>
          })
        }
      </div>
    </div>
  );
};

export default VirtualScroll;

export type { Key, MapTreeDataResult, TreeItem, VirtualScrollProps };
